#include "game.h"
#include<QApplication>
#include<QWidget>
#include<QPaintEvent>
#include<QTime>
#include<QDebug>
#include<QPainter>
#include<QMouseEvent>
#include<QPainterPath>
#include<QPen>
#include<QColor>
#include<QBrush>
#include<QMessageBox>
#include<QRadioButton>
#include<QButtonGroup>
#include<qpalette.h>
#include<QtDebug>
#include<QPushButton>
#include<QLabel>
#include<QMainWindow>


using namespace std;

const QPoint Game::m_dir[8] = {
    QPoint(-1, -1), QPoint(0, -1), QPoint(1, -1),
    QPoint(-1,  0),                 QPoint(1,  0),
    QPoint(-1,  1), QPoint(0,  1), QPoint(1,  1)
};

Game::Game(QWidget *parent):QWidget(parent) {
    //窗口标题
    setWindowTitle("wuziqi");
    setMinimumSize(1000, 800);
    setMaximumSize(1000, 800);

    QPushButton *button_s = new QPushButton(this);
    button_s -> setStyleSheet("front::Bold; font-size:36px; color:white; background-color: rgb(105,105,105);border:2px;border-radius:10px;padding:2px 4px;");

    button_s->setGeometry(QRect(800, 100, 200, 50));
    button_s->setText("游戏类型：");

    QLabel *Label = new QLabel(this);
    Label->setText("c++小游戏");
    Label->setGeometry(870, 750, 200, 50);
    Label->setStyleSheet("color: blue;font-size:24px;");

    game_type = 1;
    SelectModeGroup = new QButtonGroup(this);

    QRadioButton *PVC = new QRadioButton(tr("AI"), this);
    SelectModeGroup->addButton(PVC, 1);
    PVC->setStyleSheet("font:Bold;font-size:36px;color:red;");
    PVC->setGeometry(825, 200, 100, 30);
    connect(PVC, SIGNAL(clicked()), this, SLOT(SelectRadio()));

    QRadioButton *PVP = new QRadioButton(tr("双人"), this);
    SelectModeGroup->addButton(PVP, 2);
    PVP->setStyleSheet("font:Bond;font-size:36px;color:blue;");
    PVP->setGeometry(825, 270, 100, 30);
    QFrame::connect(PVP, SIGNAL(clicked()), this, SLOT(SelectRadio()));
    PVC->setChecked(true);
    flag = 0;
    button = new QPushButton(this);
    button->setStyleSheet("front::Bold; font-size:36px; color:white; background-color: rgb(105,105,105);border:2px;border-radius:10px;padding:2px 4px;");
    button->setGeometry(QRect(800, 390, 200, 50));
    button->setText("开始");
    connect(button, SIGNAL(clicked()), this, SLOT(oper()));

    //落子无悔 按钮
    while(!sta.empty()) {
        // sta.pop();
        sta.clear();
    }
    QPushButton *back_button = new QPushButton(this);
    back_button->setStyleSheet("QPushButton{front::Bold; font-size:36px; color:white; background-color: rgb(105,105,105);border:2px;border-radius:10px;padding:2px 4px;}");
    back_button->setGeometry(QRect(800, 520, 200, 50));
    back_button->setText("落子无悔");
    connect(back_button, SIGNAL(clicked()), this, SLOT(back()));

    //配置END
    //开启鼠标监听
    setMouseTracking(true);
    lock = 1;
    memset(board, 0, sizeof(board));

}

//PVC PVP 槽
void Game::SelectRadio(){
    switch(SelectModeGroup->checkedId()){
    case 1:
        game_type = 1;//PVC
        break;
    case 2:
        game_type = 2;//PVP
    }
}

//开始结束 按钮 槽
void Game::oper(){
    if(flag == 0){
        player = 0;
        lock = 0;
        currentX = -100;
        currentY = -100;
        moveX = -100;
        moveY = -100;
        while(!sta.empty()) {
            // sta.pop();
            sta.clear();
        }
        memset(board, 0, sizeof(board));
        button->setText("结束");
        button->setStyleSheet("font:Bold;font-size:36px;color:purple;background-color:rgb(30, 144,255);border-radius:10px;padding:2px 4px;");

    }else{
        button->setText("开始");
        button->setStyleSheet("font:Bold;font-size:36px;color:purple;background-color:rgb(30, 144,255);border-radius:10px;padding:2px 4px;");
        lock = 1;
        memset(board, 0, sizeof(board));
        update();
    }
    flag = !flag;
}
//悔棋 槽
void Game::back(){
    if(sta.empty() || flag == 0) return ;
    int num = 1;
    if(game_type == 1) num++;
    if(winner == "YOU" && lock == 1) num--;
    for(int i = 0; i < num; ++i){

        board[sta.last().x()][sta.last().y()] = 0;
        sta.removeLast();
        player--;
    }
    if(!sta.empty()){
        currentX = sta.last().x();
        currentY = sta.last().y();
    }
    else{
        currentX = -100;
        currentY = -100;
    }
    lock = 0;
    update();
}
//绘图事件
void Game::paintEvent(QPaintEvent*){
    QPainter p(this);
    //反走样
    p.setRenderHint(QPainter::TextAntialiasing, true);
    //画棋盘
    //上背景色
    QBrush brush;
    brush.setColor(QColor(230, 230, 250));
    brush.setStyle(Qt::SolidPattern);
    p.setBrush(brush);

    //边框加粗（已经取消）
    QPen pen = p.pen();
    //pen.setPen(pen);
    p.drawRect(30, 30, 740, 740);
    //棋盘网格线
    pen.setColor(Qt::black);
    pen.setWidth(1);
    p.setPen(pen);
    for(int i = 0; i < 15; ++i){
        p.drawLine(50, 50+i*50, 750, 50+i*50);
        p.drawLine(50+i*50, 50, 50+i*50, 750);
    }

    //画五个黑点
    brush.setColor(Qt::black);
    p.setBrush(brush);
    p.drawRect(195, 195, 10, 10);
    p.drawRect(595, 195, 10, 10);
    p.drawRect(195, 595, 10, 10);
    p.drawRect(595, 595, 10, 10);
    p.drawRect(395, 395, 10, 10);

    //画棋子
    brush.setStyle(Qt::SolidPattern);
    for(int i = 0; i < 15; ++i){
        for(int j = 0; j < 15; ++j){
            if(board[i][j] == 1){
                brush.setColor(Qt::black);
                p.setBrush(brush);
                p.drawEllipse(QPoint(i*50+50, j*50+50), 20, 20);
            }else if(board[i][j] == 2){
                brush.setColor(Qt::white);
                p.setPen(Qt::NoPen);
                p.setBrush(brush);
                p.drawEllipse(QPoint(i*50+50, j*50+50), 20, 20);
            }
        }
    }
    // flag == 1游戏运行 即 绘制标识框
    if(!flag) return ;
    //画最近一个落子的标志红框
    pen.setColor(Qt::red);
    pen.setWidth(1);
    p.setPen(pen);
    p.setBrush(Qt::NoBrush);
    p.drawRect(currentX*50+50 - 23, currentY*50+50-23, 46, 46);

    //产生胜负/结束游戏 即 锁棋盘 禁止下棋
    if(lock) return;
    //画选择绿图标识
    if((moveX >= 0 && moveX <= 14) && (moveY >= 0 && moveY <= 14) && board[moveX][moveY] == 0){
        brush.setColor(QColor(0, 255, 0, 150));
        p.setPen(Qt::NoPen);
        p.setBrush(brush);
        p.drawEllipse(QPoint(moveX*50+50, moveY*50+50), 20, 20);
    }


}

//输赢判断
void Game::Is_Someone_Win(int x, int y){
    QPoint p(x, y);
    if(isWin(p)){
        lock = 1;
        if(game_type == 1){
            if(board[x][y] == 1) winner = "YOU";
            else winner = "AI";
        }
        else{
            if(board[x][y] == 1) winner = "BLACK";
            else winner = "WHITE";
        }
        QMessageBox::information(nullptr, "GAME OVER", winner + " WIN", QMessageBox::Ok);

    }
}
const int CHESS_VALUE[9] = {0, 50, 100, 200, 500, 650, 2500, 10000, 30000};

QVector<QPoint> Game::GetAllDropPiecePos()
{
    QVector<QPoint> allPos;
    for(int i = 0;i < BOARD_COL;i++)
    {
        for(int j = 0;j < BOARD_ROW;j++)
        {
            if (board[i][j] == 0)
            {
                allPos.push_back(QPoint(i,j));
            }
        }
    }
    return allPos;
}

int Game::GetPieceScore(int x, int y, int player)
{
    int value = 0;
    int piece = (player == 1) ? 2 : 1;
    for(int i = 0;i < 8; i++)
    {
        int t = GetChessType(x,y,i,piece);
        value += CHESS_VALUE[t];
    }
    return value;
}

int Game::GetPosValue(int x, int y)
{
    int valueX = BOARD_COL - std::abs(x - BOARD_COL / 2);
    int valueY = BOARD_ROW - std::abs(y - BOARD_ROW / 2);
    return valueX + valueY;
}

int Game::GetChessType(int x, int y, int direction, int piece)
{
    int chessType = 0;
    int NO_PIECE = 0;
    int end = NO_PIECE;
    int num = GetLinePieceNum(x,y,direction,piece,end);
    if(num == 5)
    {
        chessType = 8;
    }
    else if(num == 4 && end == NO_PIECE)
    {
        chessType = 7;
    }
    else if (num == 4 && end != NO_PIECE)
    {
        chessType = 6;
    }
    else if (num == 3 && end == NO_PIECE)
    {
        chessType = 5;
    }
    else if (num == 3 && end != NO_PIECE)
    {
        chessType = 4;
    }
    else if (num == 2 && end == NO_PIECE)
    {
        chessType = 3;
    }
    else if (num == 2 && end != NO_PIECE)
    {
        chessType = 2;
    }
    else if (num == 1 && end == NO_PIECE)
    {
        chessType = 1;
    }
    else
    {
        chessType = 0;
    }
    return chessType;
}

int Game::GetLinePieceNum(int x, int y, int direction, int pieceColor, int &pieceEnd)
{
    int offset[8][2] = {{1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}};
    int num = 0;
    x += offset[direction][0];
    y += offset[direction][1];
    if(IsBeyond(x,y) || board[x][y] != pieceColor)
    {
        return 0;
    }
    int pieceStart = board[x][y];
    while(!IsBeyond(x,y) && board[x][y] == pieceStart)
    {
        x += offset[direction][0];
        y += offset[direction][1];
        num++;
    }
    pieceEnd = board[x][y];     // 终止处的棋子
    return num;
}

bool Game::IsBeyond(int x, int y)
{
    return x < 0 || x >= BOARD_COL || y < 0 || y >=  BOARD_ROW;
}

//dir方向 offset 位移 的棋子类型
int Game::getPointAt(QPoint p, int dir, int offset){
    int y = p.y();
    int x = p.x();

    y = y + offset*m_dir[dir].y();
    x = x + offset*m_dir[dir].x();

    if(y<0||x<0||x>=15||y>=15)
        return -100;

    return board[x][y];

}
//是否五子连珠
int Game::isWin(QPoint p) {
    int dir_cnt[8] = {0};

    memset(dir_cnt, 0, sizeof(dir_cnt));
    for(int i = 0; i < 8; ++i){
        for(int j = 1;; ++j){
            if(getPointAt(p, i , j) != board[p.x()][p.y()])
                break;
            dir_cnt[i]++;
        }
    }
    for(int i = 0; i < 4; ++i){
        if(dir_cnt[i] + dir_cnt[i+4] + 1 >= 5){//五子连珠
            return 1;
        }
    }
    return 0;
}

//鼠标移动
void Game::mouseMoveEvent (QMouseEvent *event){
    moveX = (event->pos().x() + 25)/50 - 1;
    moveY = (event->pos().y() + 25)/50 - 1;
    update();
}

// 鼠标按压 下棋
void Game::mousePressEvent(QMouseEvent *e){
    if(lock) return ;
    if(!(game_type == 1 && (player&1))){
        PERSON_time(e);
        if(lock == 0 && game_type == 1 && (player&1)){
            AI_time();
        }
    }
    update();
}

//更新棋盘
void Game::update_chessboard(int x, int y){
    if(!board[x][y]){
        board[x][y] = player++ %2 + 1;
        currentX = x;
        currentY = y;
        QPoint p(x, y);
        sta.append(p);
        update();
        Is_Someone_Win(x, y);
    }
}

//人 下棋
void Game::PERSON_time(QMouseEvent *e){

    int x, y;
    if((e->pos().x() >= 25 && e->pos().x() <= 775) && (e->pos().y() >= 25 && e->pos().y() <= 775)){
        x = (e->pos().x() + 25) / 50 - 1;
        y = (e->pos().y() + 25) / 50 - 1;
        update_chessboard(x, y);
    }
}

//AI 下棋
void Game::AI_time(){

    int bestScore = -20000;
    QPoint bestPos;
    for(QPoint pos : GetAllDropPiecePos())
    {
        int value = GetPieceScore(pos.x(),pos.y(),0);
        int oppoValue = GetPieceScore(pos.x(),pos.y(),1);
        int totalValue = std::max(value,oppoValue * 4/5);
        if(totalValue > bestScore)
        {
            bestScore = totalValue;
            bestPos = pos;
        }
    }
    update_chessboard(bestPos.x(), bestPos.y());

}
